/*
 * CC3OpenGLES11Matrices.m
 *
 * cocos3d 0.6.1
 * Author: Bill Hollings
 * Copyright (c) 2011 The Brenwill Workshop Ltd. All rights reserved.
 * http://www.brenwill.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * http://en.wikipedia.org/wiki/MIT_License
 * 
 * See header file CC3OpenGLES11Matrices.h for full API documentation.
 */

#include "CC3OpenGLES11Matrices.h"


#pragma mark -
#pragma mark CC3OpenGLES11MatrixStack

//@implementation CC3OpenGLES11MatrixStack
//
//-(void) dealloc {
//	[modeTracker release];
//	[super dealloc];
//}
//
//-(void) activate {
//	modeTracker.value = mode;
//}
//
//-(void) push {
//	[self activate];
//	glPushMatrix();
//	LogTrace("%@ %@ pushed", [self class], NSStringFromGLEnum(mode));
//}
//
//-(void) pop {
//	[self activate];
//	glPopMatrix();
//	LogTrace("%@ %@ popped", [self class], NSStringFromGLEnum(mode));
//}
//
//-(GLuint) getDepth {
//	[self activate];
//	GLuint depth;
//	glGetIntegerv(depthName, (GLint*)&depth);
//	LogTrace("%@ %@ read GL stack depth %u", [self class], NSStringFromGLEnum(mode), depth);
//	return depth;
//}
//
//-(void) identity {
//	[self activate];
//	glLoadIdentity();
//	LogTrace("%@ %@ loaded identity", [self class], NSStringFromGLEnum(mode));
//}
//
//-(void) load: (GLvoid*) glMatrix {
//	[self activate];
//	glLoadMatrixf(glMatrix);
//	LogTrace("%@ %@ loaded matrix at %p", [self class], NSStringFromGLEnum(mode), glMatrix);
//}
//
//-(void) getTop: (GLvoid*) glMatrix {
//	[self activate];
//	glGetFloatv(topName, glMatrix);
//	LogTrace("%@ %@ read top into %p", [self class], NSStringFromGLEnum(mode), glMatrix);
//}
//
//-(void) multiply: (GLvoid*) glMatrix {
//	[self activate];
//	glMultMatrixf(glMatrix);
//	LogTrace("%@ %@ multiplied matrix at %p", [self class], NSStringFromGLEnum(mode), glMatrix);
//}
//
//-(id) initWithMode: (GLenum) matrixMode
//		andTopName: (GLenum) tName
//	  andDepthName: (GLenum) dName
//	andModeTracker: (CC3OpenGLES11StateTrackerEnumeration*) tracker {
//	if ( (self = [super init]) ) {
//		mode = matrixMode;
//		topName = tName;
//		depthName = dName;
//		modeTracker = [tracker retain];
//	}
//	return self;
//}
//
//+(id) trackerWithMode: (GLenum) matrixMode
//		   andTopName: (GLenum) tName
//		 andDepthName: (GLenum) dName
//	   andModeTracker: (CC3OpenGLES11StateTrackerEnumeration*) tracker {
//	return [[[self alloc] initWithMode: matrixMode
//							andTopName: tName
//						  andDepthName: dName
//						andModeTracker: tracker] autorelease];
//}
//
//@end

CC3OpenGLES11MatrixStack::CC3OpenGLES11MatrixStack() :
	modeTracker(NULL)
{
}

CC3OpenGLES11MatrixStack::~CC3OpenGLES11MatrixStack()
{
	modeTracker->release();
}

CC3OpenGLES11MatrixStack* CC3OpenGLES11MatrixStack::trackerWithMode(GLenum matrixMode, 
												 GLenum tName, 
												 GLenum dName, 
												 CC3OpenGLES11StateTrackerEnumeration* tracker)
{
	CC3OpenGLES11MatrixStack* pStack = new CC3OpenGLES11MatrixStack;
	if (pStack) 
	{
		pStack->autorelease();
		pStack->initWithMode(matrixMode, tName, dName, tracker);
		return pStack;
	}
	return NULL;
}

CC3OpenGLES11MatrixStack* CC3OpenGLES11MatrixStack::initWithMode(GLenum matrixMode, 
									   GLenum tName, 
									   GLenum dName, 
									   CC3OpenGLES11StateTrackerEnumeration* tracker)
{
	mode = matrixMode;
	topName = tName;
	depthName = dName;
	modeTracker = tracker;
	modeTracker->retain();
	return this;
}

void CC3OpenGLES11MatrixStack::activate()
{
	modeTracker->setValue(mode);
}

void CC3OpenGLES11MatrixStack::push()
{
	activate();
	glPushMatrix();
	//LogTrace("%@ %@ pushed", [self class], NSStringFromGLEnum(mode));
}

void CC3OpenGLES11MatrixStack::pop()
{
	activate();
	glPopMatrix();
	//LogTrace("%@ %@ popped", [self class], NSStringFromGLEnum(mode));
}

GLuint CC3OpenGLES11MatrixStack::getDepth()
{
	activate();
	GLuint depth;
	glGetIntegerv(depthName, (GLint*)&depth);
	//LogTrace("%@ %@ read GL stack depth %u", [self class], NSStringFromGLEnum(mode), depth);
	return depth;
}

void CC3OpenGLES11MatrixStack::identity()
{
	activate();
	glLoadIdentity();
	//LogTrace("%@ %@ loaded identity", [self class], NSStringFromGLEnum(mode));
}

void CC3OpenGLES11MatrixStack::load(GLvoid* glMatrix)
{
	activate();
	glLoadMatrixf((const GLfloat *)glMatrix);
	//LogTrace("%@ %@ loaded matrix at %p", [self class], NSStringFromGLEnum(mode), glMatrix);
}

void CC3OpenGLES11MatrixStack::getTop(GLvoid* glMatrix)
{
	activate();
	glGetFloatv(topName, (GLfloat *)glMatrix);
	//LogTrace("%@ %@ read top into %p", [self class], NSStringFromGLEnum(mode), glMatrix);
}

void CC3OpenGLES11MatrixStack::multiply(GLvoid* glMatrix)
{
	activate();
	glMultMatrixf((const GLfloat *)glMatrix);
	//LogTrace("%@ %@ multiplied matrix at %p", [self class], NSStringFromGLEnum(mode), glMatrix);
}


#pragma mark -
#pragma mark CC3OpenGLES11Matrices

//@implementation CC3OpenGLES11Matrices
//
//@synthesize mode;
//@synthesize modelview;
//@synthesize projection;
//
//-(void) dealloc {
//	[mode release];
//	[modelview release];
//	[projection release];
//
//	[super dealloc];
//}
//
//-(void) initializeTrackers {
//	// Matrix mode tracker needs to read and restore
//	self.mode = [CC3OpenGLES11StateTrackerEnumeration trackerForState: GL_MATRIX_MODE
//													 andGLSetFunction: glMatrixMode
//											 andOriginalValueHandling: kCC3GLESStateOriginalValueReadOnceAndRestore];
//
//	self.modelview = [CC3OpenGLES11MatrixStack trackerWithMode: GL_MODELVIEW 
//													andTopName: GL_MODELVIEW_MATRIX
//												  andDepthName: GL_MODELVIEW_STACK_DEPTH
//												andModeTracker: mode];
//
//	self.projection = [CC3OpenGLES11MatrixStack trackerWithMode: GL_PROJECTION 
//													andTopName: GL_PROJECTION_MATRIX
//												  andDepthName: GL_PROJECTION_STACK_DEPTH
//												andModeTracker: mode];
//}
//
//-(void) open {
//	LogTrace("Opening %@", [self class]);
//	[mode open];
//	[modelview open];
//	[projection open];
//}
//
//-(void) close {
//	LogTrace("Closing %@", [self class]);
//	[mode close];
//	[modelview close];
//	[projection close];
//}
//
//-(NSString*) description {
//	NSMutableString* desc = [NSMutableString stringWithCapacity: 600];
//	[desc appendFormat: @"%@:", [self class]];
//	[desc appendFormat: @"\n    %@ ", mode];
//	[desc appendFormat: @"\n    %@ ", modelview];
//	[desc appendFormat: @"\n    %@ ", projection];
//	return desc;
//}
//
//@end

CC3OpenGLES11Matrices::CC3OpenGLES11Matrices() :
	mode(NULL),
	modelview(NULL),
	projection(NULL)
{
	
}

CC3OpenGLES11Matrices::~CC3OpenGLES11Matrices()
{
	mode->release();
	modelview->release();
	projection->release();
}

CC3OpenGLES11Matrices* CC3OpenGLES11Matrices::tracker()
{
	CC3OpenGLES11Matrices* pState = new CC3OpenGLES11Matrices;
	if (pState) 
	{
		pState->initializeTrackers();
		pState->autorelease();
	}
	
	return pState;
}

void CC3OpenGLES11Matrices::open()
{
	//LogTrace("Opening %@", [self class]);
	mode->open();
	modelview->open();
	projection->open();
}

void CC3OpenGLES11Matrices::close()
{
	//LogTrace("Closing %@", [self class]);
	mode->close();
	modelview->close();
	projection->close();
}

void CC3OpenGLES11Matrices::initializeTrackers()
{
	setMode(CC3OpenGLES11StateTrackerEnumeration::trackerForState(GL_MATRIX_MODE,
																 glMatrixMode,
																 kCC3GLESStateOriginalValueReadOnceAndRestore));
				 
	setModelview(CC3OpenGLES11MatrixStack::trackerWithMode(GL_MODELVIEW,
														  GL_MODELVIEW_MATRIX,
														  GL_MODELVIEW_STACK_DEPTH,
														  mode));
 
	setProjection(CC3OpenGLES11MatrixStack::trackerWithMode(GL_PROJECTION,
														   GL_PROJECTION_MATRIX,
														   GL_PROJECTION_STACK_DEPTH,
														   mode));
}


